package com.thinkingcoder.tccache.core.operator;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import com.thinkingcoder.tccache.core.model.CacheEntry;

/**
 * List operator.
 */
public class ListOperator extends AbstractOperator {

    public int lPush(String key, String... values) {
        CacheEntry<?> cacheEntry = getOrInitCacheEntry(key);
        LinkedList<String> exist = (LinkedList<String>)cacheEntry.getValue();
        if (values == null || values.length == 0) {
            return 0;
        }
        Arrays.stream(values).forEach(exist::addFirst);
        return values.length;
    }

    public String[] lPop(String key, int count) {
        if (checkInvalid(key)) {
            return null;
        }
        LinkedList<String> value = getListEntryValue(key);
        if (value == null) {
            return null;
        }
        int len = Math.min(value.size(), count);
        String[] ret = new String[len];
        for (int idx = 0; idx < len; idx++) {
            ret[idx] = value.removeFirst();
        }
        return ret;
    }

    public int rPush(String key, String[] values) {
        CacheEntry<?> cacheEntry = getOrInitCacheEntry(key);
        LinkedList<String> exist = (LinkedList<String>)cacheEntry.getValue();

        if (values == null || values.length == 0) {
            return 0;
        }

        exist.addAll(List.of(values));
        return values.length;
    }

    public String[] rPop(String key, int count) {
        if (checkInvalid(key)) {
            return null;
        }
        LinkedList<String> value = getListEntryValue(key);
        if (value == null) {
            return null;
        }
        int len = Math.min(value.size(), count);
        String[] ret = new String[len];
        for (int idx = 0; idx < len; idx++) {
            ret[idx] = value.removeLast();
        }
        return ret;
    }

    public int lLen(String key) {
        if (checkInvalid(key)) {
            return 0;
        }

        LinkedList<String> value = getListEntryValue(key);
        return value == null ? 0 : value.size();
    }

    public String lIndex(String key, int index) {
        if (checkInvalid(key)) {
            return null;
        }

        LinkedList<String> value = getListEntryValue(key);
        if (value == null || index >= value.size()) {
            return null;
        }
        return value.get(index);
    }

    public String[] lRange(String key, int startIndex, int endIndex) {
        if (checkInvalid(key)) {
            return null;
        }

        LinkedList<String> value = getListEntryValue(key);
        if (value == null) {
            return null;
        }

        int size = value.size();
        int len = Math.min(size - startIndex, endIndex - startIndex + 1);
        String[] ret = new String[len];
        for (int i = 0; i < len; i++) {
            ret[i] = value.get(startIndex + i);
        }
        return ret;
    }

    private CacheEntry<?> getOrInitCacheEntry(String key) {
        CacheEntry<?> cacheEntry = getCacheEntry(key);
        if (cacheEntry == null) {
            synchronized (getMap()) {
                if ((cacheEntry = getCacheEntry(key)) == null) {
                    cacheEntry = new CacheEntry<>(new LinkedList<>(), System.currentTimeMillis(), -1000L);
                    putCacheEntry(key, cacheEntry);
                }
            }
        }
        return cacheEntry;
    }

    private LinkedList<String> getListEntryValue(String key) {
        return (LinkedList<String>)getCacheEntryValue(key);
    }

}
